package com.demo.common.utils;

import cn.hutool.core.util.StrUtil;
import com.demo.common.enums.BaseOptionEnum;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.reflections.Reflections;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.*;

/**
 * 枚举方法封装
 *
 * @author Zsx
 */
@Slf4j
public class EnumUtils {
    /**
     * 根据反射，通过方法名称获取方法值，忽略大小写的
     *
     * @param methodName 方法名
     * @param obj        枚举对象
     * @param args       参数
     * @return return value
     */
    private static <T> Object getMethodValue(String methodName, T obj,
                                             Object... args) {
        Object resut = "";
        // boolean isHas = false;
        try {
            //获取方法数组，这里只要共有的方法
            Method[] methods = obj.getClass().getMethods();
            if (methods.length <= 0) {
                return resut;
            }

            Method method = null;
            for (Method value : methods) {
                //忽略大小写取方法
                if (value.getName().equalsIgnoreCase(methodName)) {
                    method = value;
                    break;
                }
            }

            if (method == null) {
                return resut;
            }
            //方法执行
            resut = method.invoke(obj, args);
            if (resut == null) {
                resut = "";
            }
            return resut;
        } catch (Exception e) {
            log.debug("获取枚举方法值出错", e);
        }
        return resut;
    }

    /**
     * 枚举转map结合value作为map的key,name作为map的value
     *
     * @param tClass      枚举类
     * @param methodNames 方法名
     * @return enum mapcolloction
     */
    public static <T> Map<Object, String> enumToMap(Class<T> tClass, String... methodNames) {
        Map<Object, String> enumMap = new HashMap<>();
        if (!tClass.isEnum()) {
            return enumMap;
        }
        T[] enums = tClass.getEnumConstants();
        if (enums == null || enums.length <= 0) {
            return enumMap;
        }
        int count = methodNames.length;
        //默认接口value方法
        String valueMethod = "getValue";
        //默认接口name方法
        String desMethod = "getName";
        //扩展方法
        if (count >= 1 && StrUtil.isNotBlank(methodNames[0])) {
            valueMethod = methodNames[0];
        }
        if (count == 2 && StrUtil.isNotBlank(methodNames[1])) {
            desMethod = methodNames[1];
        }
        for (T tObj : enums) {
            try {
                //获取value值
                Object resultValue = getMethodValue(valueMethod, tObj);
                if ("".equals(resultValue)) {
                    continue;
                }
                //获取description描述值
                Object resultDes = getMethodValue(desMethod, tObj);
                //如果描述不存在获取属性值
                if ("".equals(resultDes)) {
                    resultDes = tObj;
                }
                enumMap.put(resultValue, resultDes + "");
            } catch (Exception e) {
                log.debug("枚举转Map出错", e);
            }
        }
        return enumMap;
    }

    /**
     * 将所有实现OptionsEnum的枚举统一处理为选项数据后返回
     *
     * @return 选项的数据
     */
    @SuppressWarnings("unchecked")
    public static Map<String, Object> enumsToOptions() {

        Reflections reflections = new Reflections("com.demo.common.enums");
        Set classes = reflections.getSubTypesOf(BaseOptionEnum.class);

        Map<String, Object> options = new HashMap<>(classes.size());
        for (Object aClass : classes) {
            Class c = (Class) aClass;
            String enumsKey = toLowerCaseFirstOne(c.getSimpleName().replaceAll("Enum", ""));
            List<Map<String, Object>> m = enumToMapList(c);
            options.put(enumsKey, m);
        }
        return options;
    }

    /**
     * 将枚举类转换为选项集合
     * 枚举需要包含属性code和name
     *
     * @param enm 枚举类class
     * @return 集合
     */
    @SneakyThrows
    private static <T> List<Map<String, Object>> enumToMapList(Class<T> enm) {
        List<Map<String, Object>> enumList = new ArrayList<>();
        if (!enm.isEnum()) {
            return enumList;
        }
        T[] enums = enm.getEnumConstants();
        for (T e : enums) {
            Map<String, Object> eMap = new HashMap<>(2);
            Method codeMethod = ReflectionUtils.findMethod(e.getClass(), "getValue");
            Method nameMethod = ReflectionUtils.findMethod(e.getClass(), "getName");
            Object code = "";
            if (codeMethod != null) {
                code = ReflectionUtils.invokeMethod(codeMethod, e);
            }
            String name = "";
            if (nameMethod != null) {
                name = (String) ReflectionUtils.invokeMethod(nameMethod, e);
            }
            eMap.put(code.toString(), name);
            enumList.add(eMap);
        }
        return enumList;
    }

    /**
     * 字符串首字母小写
     */
    private static String toLowerCaseFirstOne(String s) {
        if (Character.isLowerCase(s.charAt(0))) {
            return s;
        } else {
            return Character.toLowerCase(s.charAt(0)) + s.substring(1);
        }
    }
}
